package com.hnu.store.service.impl;

import com.alibaba.fastjson.JSON;
import com.hnu.store.dto.UserDTO;
import com.hnu.store.entity.User;
import com.hnu.store.mapper.UserMapper;
import com.hnu.store.service.IUserService;
import com.hnu.store.service.ex.CertifyException;
import com.hnu.store.service.ex.ChangeInfoException;
import com.hnu.store.service.ex.EmailException;
import com.hnu.store.service.ex.FileNotFoundException;
import com.hnu.store.service.ex.InsertException;
import com.hnu.store.service.ex.PasswordNotMatchException;
import com.hnu.store.service.ex.ServiceException;
import com.hnu.store.service.ex.UploadException;
import com.hnu.store.service.ex.UserNotExistException;
import com.hnu.store.service.ex.UsernameDuplicateException;
import com.hnu.store.utils.Certificate;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * 用户模块业务层的实现类
 */
@Service
//  @Service注解的作用是将对象交给spring来处理
public class UserServiceImpl implements IUserService {

  @Autowired
  private UserMapper userMapper;

  @Override
  public void register(User user) {
    String username = user.getUsername();
    User result = userMapper.findByUsername(username);
    /*
      如果查询不到用户名，则告知用户名被占用了
     */

    if (result != null) {
      throw new UsernameDuplicateException("用户名被占用");
    }
    /*
      补全user的数据
      目前只有用户名、密码、邮箱
     */
    user.setAvatar("default.jpg");
    //  用户界面注册只能注册普通用户，管理员用户由内部设置数据库字段
    user.setIsAdmin(0);
    user.setIsCertified(0);
    user.setCreatedUser(username);
    user.setModifiedUser(username);
    Date date = new Date();
    user.setModifiedTime(date);
    user.setCreatedTime(date);

    String oldPassword = user.getPassword();
    String salt = UUID.randomUUID().toString().toUpperCase();
    //  插入注册的用户数据，插入之前补全user的数据的同时，对密码进行加密
    String MD5Password = getMD5Password(oldPassword, salt);
    user.setSalt(salt);
    user.setPassword(MD5Password);

    //  插入数据库完成注册
    Integer rows = userMapper.insert(user);
    if (rows != 1) {
      throw new InsertException("产生了未知的异常");
    }

  }

  @Autowired
  JavaMailSenderImpl mailSender;

  @Override
  public String sendCaptcha(String receiver) {

    String captcha = String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
    SimpleMailMessage message = new SimpleMailMessage();
    message.setSubject("HNU_NFT数字作品交易平台");  //设置邮件标题
    message.setText("尊敬的用户,您好:\n"
        + "\n本次请求的邮件验证码为:" + captcha + "\n如非本人操作，请忽略该邮件。");  //设置邮件正文
    message.setTo(receiver);  //设置收件人
    message.setFrom("Geo0426@hnu.edu.cn");  //设置发件人
    try {
      mailSender.send(message);  //发送邮件
    } catch (MailException e) {
      throw new EmailException("验证码发送失败");
    }
    return captcha;
  }

  @Override
  public UserDTO login(String username, String password) {
    User result = userMapper.findByUsername(username);
    if (result == null) {
      throw new UserNotExistException();
    }
    //  获取MD5加密后的密码
    String salt = result.getSalt();
    String MD5Password = getMD5Password(password, salt);
    if (!MD5Password.equals(result.getPassword())) {
      throw new PasswordNotMatchException();
    }

    //  登录成功,返回该用户
    UserDTO dto = new UserDTO();
    if (result.getIsAdmin() == 1) {
      dto.setIsAdmin(1);
    }
    //  基本数据全部返回
    dto.setEmail(result.getEmail());
    dto.setId(result.getId());
    dto.setAvatar(result.getAvatar());
    dto.setUsername(result.getUsername());
    dto.setPocket(result.getPocket());
    dto.setIsCertified(result.getIsCertified());
    dto.setPhone(result.getPhone());
    dto.setRealName(result.getRealName());
    dto.setCitizenId(result.getCitizenId());
    dto.setTag1(result.getTag1());
    dto.setTag2(result.getTag2());
    dto.setTag3(result.getTag3());
    dto.setFront(result.getFront());
    dto.setNegative(result.getNegative());
    return dto;
  }

  @Override
  //  计划是前端axios传输的过程中将username,phone,email全部传过来组成一个user,id另外传
  public UserDTO changeInformation(Integer userId, User user) {
    User result = userMapper.findById(userId);
    //   导入的id没用对应的用户（一般不会存在这种情况）
    if (result == null) {
      throw new UserNotExistException("前端存储用户id错误或被篡改");
    }

    user.setId(userId);
    user.setModifiedUser(user.getUsername());
    user.setModifiedTime(new Date());

    int rows = userMapper.updateUserInfo(user);

    //  如果修改的行数不为1，抛出修改异常
    if (rows != 1) {
      throw new ChangeInfoException("修改信息过程中的未知错误");
    }
    //  更新后的数据
    result = userMapper.findById(userId);
    //  封装到DTO里传给前端
    return new UserDTO(result.getId(), result.getUsername(), result.getPhone(),
        result.getEmail(), result.getCitizenId(), result.getPocket(), result.getAvatar(),
        result.getIsAdmin(), result.getIsCertified(), result.getRealName(),
        result.getTag1(), result.getTag2(), result.getTag3(), result.getFront(),
        result.getNegative());
    //11.9
  }

  //11.12 dl
  @Override
  public User getUserById(Integer userid) {
    User user = userMapper.findById(userid);
    if (user == null) {
      throw new UserNotExistException("用户不存在");
    }

    return user;
  }

  @Override
  public void changePassword(String username, String password) {
    User user = userMapper.findByUsername(username);
    String salt = user.getSalt();

    if (userMapper.updatePassword(username, getMD5Password(password, salt)) != 1) {
      throw new ChangeInfoException("修改密码失败");
    }

  }
  //11.12


  @Override
  public UserDTO setTags(String username, String tag1, String tag2, String tag3) {

    if (userMapper.setTags(username, tag1, tag2, tag3) != 1) {
      throw new ChangeInfoException("修改标签过程中的未知错误");
    }
    //  修改后从数据库读取user
    User user = userMapper.findByUsername(username);
    //  封装到dto里返回

    return new UserDTO(user.getId(), user.getUsername(), user.getPhone(), user.getEmail(),
        user.getCitizenId(), user.getPocket(), user.getAvatar(), user.getIsAdmin(),
        user.getIsCertified(),user.getRealName(), user.getTag1(),
        user.getTag2(), user.getTag3(),user.getFront(),user.getNegative());
  }

  @Override
  public void setPocket(String username, String pocket) {
    if (userMapper.setPocket(username, pocket) != 1) {
      throw new ChangeInfoException("设置钱包地址失败");
    }
  }

  @Override
  public void setAvatar(Integer id, MultipartFile multipartFile) {
    String path = System.getProperty("user.dir") + File.separator + "user" + File.separator + id;
    String fileName = multipartFile.getOriginalFilename();
    File dir = new File(path);
    File newAvatar = new File(dir, Objects.requireNonNull(multipartFile.getOriginalFilename()));
    //  得到用户来获取原头像文件名
    User user = userMapper.findById(id);
    if (!dir.exists()) {
      dir.mkdirs();
      //  创建文件夹直接上传头像
      try {
        multipartFile.transferTo(newAvatar);
      } catch (IOException e) {
        throw new UploadException("头像上传异常");
      }
      //  更新数据库
      if (userMapper.setAvatar(id, fileName) != 1) {
        throw new ChangeInfoException("数据库更新头像失败");
      }
    } else {
      File oldAvatar = new File(path + File.separator + user.getAvatar());
      //  旧文件删除成功
      if (oldAvatar.delete()) {
        //  上传新头像
        try {
          multipartFile.transferTo(newAvatar);
        } catch (IOException e) {
          throw new UploadException("头像更新异常");
        }
        //  更新数据库
        if (userMapper.setAvatar(id, fileName) != 1) {
          throw new ChangeInfoException("数据库更新头像失败");
        }
      } else {
        throw new ChangeInfoException("旧头像删除失败");
      }
    }
  }

  @Override
  public void getAvatar(String username, HttpServletResponse response) {
    User user = userMapper.findByUsername(username);
    File file = null;
    //  默认头像或者用户头像
    if (user.getAvatar().equals("default.jpg")) {
      file = new File(System.getProperty("user.dir") + File.separator + "user" + File.separator
          + "default.jpg");
    } else {
      file = new File(
          System.getProperty("user.dir") + File.separator + "user" + File.separator + user.getId()
              + File.separator + user.getAvatar());
    }

    if (!file.exists()) {
      throw new FileNotFoundException("http请求的文件不存在");
    }
    //  配置文件下载
    response.setHeader("content-type", "application/octet-stream");
    response.setContentType("application/octet-stream");
    // 下载文件能正常显示中文
    response.setHeader("Content-Disposition",
        "attachment;filename=" + user.getAvatar());
    // 实现文件下载
    byte[] buffer = new byte[1024];
    try {
      FileInputStream fis = new FileInputStream(file);
      OutputStream os = response.getOutputStream();
      while ((fis.read(buffer)) != -1) {
        os.write(buffer);
        os.flush();
      }
      os.close();
    } catch (Exception e) {
      System.out.println("写入HttpServletResponse错误" + e);
      e.printStackTrace();
    }
  }

  @Override
  public User getUserByUsername(String username) {
    User user = userMapper.findByUsername(username);
    if (user == null) {
      throw new UserNotExistException("用户不存在");
    }
    return user;
  }

  @Override
  public void certify(MultipartFile front, MultipartFile negative, Integer id) {
    String filePath = System.getProperty("user.dir") + File.separator + "user" + File.separator + id;
    File fileDir = new File(filePath);
    if (!fileDir.exists() && !fileDir.isDirectory()) {
      fileDir.mkdirs();
    }

    File file1 = new File(
        filePath + File.separator + front.getOriginalFilename());
    File file2 = new File(
        filePath + File.separator + negative.getOriginalFilename());

    try {
      front.transferTo(file1);
      negative.transferTo(file2);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }

    Map result = Certificate.certify(Certificate.fileToBase64(file1),
        Certificate.fileToBase64(file2));
    String code = String.valueOf(result.get("code"));

    if (code.equals("200")) {
      User user = userMapper.findById(id);
      String dataString = result.get("data").toString();
      Map data = JSON.parseObject(dataString,Map.class);
      //  json数据中获取身份证号码和真实姓名完成实名认证
      user.setCitizenId(String.valueOf(data.get("idcard")));
      user.setRealName(String.valueOf(data.get("name")));
      //  设置实名认证的标志
      user.setIsCertified(1);
      user.setFront(front.getOriginalFilename());
      user.setNegative(negative.getOriginalFilename());
      userMapper.updateUserInfo(user);
    } else {
      //  实名认证失败，删除上传的身份证
      file1.delete();
      file2.delete();
      throw new CertifyException("实名认证失败");
    }


  }

  /**
   * 获取实名认证信息
   *
   * @param username 用户名
   * @param response http的response
   */
  @Override
  public void getCertification(String username, String type, HttpServletResponse response) {
    User user = userMapper.findByUsername(username);
    File file;

    if (type.equals("front")) {
      file = new File(
          System.getProperty("user.dir") + File.separator + "user" + File.separator + user.getId()
              + File.separator + user.getFront());
    } else if (type.equals("negative")) {
      file = new File(
          System.getProperty("user.dir") + File.separator + "user" + File.separator + user.getId()
              + File.separator + user.getNegative());
    } else {
      throw new ServiceException("身份证获取错误");
    }

    if (!file.exists()) {
      throw new FileNotFoundException("http请求的文件不存在");
    }
    //  配置文件下载
    response.setHeader("content-type", "application/octet-stream");
    response.setContentType("application/octet-stream");
    // 下载文件能正常显示中文
    response.setHeader("Content-Disposition",
        "attachment;filename=" + user.getAvatar());
    // 实现文件下载
    byte[] buffer = new byte[1024];
    try {
      FileInputStream fis = new FileInputStream(file);
      OutputStream os = response.getOutputStream();
      while ((fis.read(buffer)) != -1) {
        os.write(buffer);
        os.flush();
      }
      os.close();
    } catch (Exception e) {
      System.out.println("写入HttpServletResponse错误" + e);
      e.printStackTrace();
    }
  }



  /**
   * md5算法加密
   */
  private String getMD5Password(String password, String salt) {
    for (int i = 0; i < 3; i++) {
      password = DigestUtils.md5DigestAsHex((salt + password + salt).getBytes()).toUpperCase();
    }
    return password;
  }

}
